package org.zoomdev.zoom;


// Argon2哈希示例

import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
import org.bouncycastle.crypto.params.Argon2Parameters;
import org.zoomdev.zoom.common.caster.Base64;

import java.security.MessageDigest;
import java.util.concurrent.ThreadLocalRandom;

public class Argon2Util {
    // 不可变静态配置
    public static boolean verifyPassword(String inputPassword, String storedHash) {
        // 解析存储的哈希字符串
        String[] parts = storedHash.split("\\$");
        if (parts.length != 6)
            throw new IllegalArgumentException("Invalid hash format");

        // 提取参数
        String saltBase64 = parts[4];
        String storedHashBase64 = parts[5];
        byte[] salt = Base64.decode(saltBase64);
        byte[] storedHashBytes = Base64.decode(storedHashBase64);

        // 使用相同参数重新计算哈希
        Argon2Parameters params = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withSalt(salt)
                .withIterations(5)
                .withMemoryAsKB(65536)
                .withParallelism(2)
                .build();

        Argon2BytesGenerator generator = new Argon2BytesGenerator();
        generator.init(params);
        byte[] inputHash = new byte[32];
        generator.generateBytes(inputPassword.toCharArray(), inputHash);

        // 恒定时间比较
        return MessageDigest.isEqual(inputHash, storedHashBytes);
    }

    public static String hash(String password) {
        // 动态生成盐值
        byte[] salt = getRandomBytes(16);

        // 配置参数
        Argon2Parameters params = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withSalt(salt)
                .withIterations(5)
                .withMemoryAsKB(65536) // 64 MB
                .withParallelism(2)
                .build();

        // 生成哈希
        Argon2BytesGenerator generator = new Argon2BytesGenerator();
        generator.init(params);
        byte[] hash = new byte[32];
        generator.generateBytes(password.toCharArray(), hash);

        // 编码为存储字符串
        return String.format("$argon2id$v=19$m=%d,t=%d,p=%d$%s$%s",
                params.getMemory(),
                params.getIterations(),
                params.getLanes(),
                Base64.encodeToString(salt),
                Base64.encodeToString(hash));
    }

    private static Argon2Parameters createStaticConfig() {
        return new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
                .withIterations(5)
                .withMemoryAsKB(65536)
                .withParallelism(2)
                .build();
    }

    private static byte[] getRandomBytes(int len) {
        byte[] bytes = new byte[len];
        ThreadLocalRandom random = ThreadLocalRandom.current();
        random.nextBytes(bytes);
        return bytes;
    }
}